
package com.goldsand.collaboration.handoff.client.connection;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.goldsand.collaboration.handoff.common.connection.BroadcastReceiveThread;
import com.goldsand.collaboration.handoff.common.connection.BroadcastSenderTask;
import com.goldsand.collaboration.handoff.common.connection.BroadcastSenderTask.SendDoneListener;
import com.goldsand.collaboration.handoff.common.connection.NewMessageListener;

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

public class SocketClientService extends Service implements NewMessageListener {
    private static final String TAG = "SocketClientService";
    private static final int CLIENT_BROADCAST_THREAD_PORT = 10082;
    private static final int SERVER_PROADCAST_THREAD_PORT = 10083;

    private static final String ACTION_CLIENT_INT = "com.goldsand.collaboration.handoff.client_IN";
    private static final String ACTION_CLIENT_OUT = "com.goldsand.collaboration.handoff.client_OUT";

    private BroadcastReceiveThread mServerBroadcastReceiveThread = null;
    private ClientConnectionThread mSocketClientThread = null;
    private String mServerIp;
    private int mServerPort;
    private List<NewMessageListener> mListeners = new ArrayList<NewMessageListener>();

    public static Intent createClientInIntent() {
        return new Intent(ACTION_CLIENT_INT);
    }

    public static Intent createClientOutIntent() {
        return new Intent(ACTION_CLIENT_OUT);
    }

    public void addMessageListener(NewMessageListener listener) {
        synchronized (mListeners) {
            mListeners.add(listener);
        }
    }

    public void removeMessageListener(NewMessageListener listener) {
        synchronized (mListeners) {
            mListeners.remove(listener);
        }
    }

    private void publishMessage(String message) {
        synchronized (mListeners) {
            for (NewMessageListener listener : mListeners) {
                listener.onNewMessageReceived(null, message);
            }
        }
    }

    public void sendMessageToServer(String message) {
        if (mSocketClientThread.isConnected()) {
            try {
                mSocketClientThread.sendDataToClient(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            Log.e(TAG, "Socket do not connected");
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mServerBroadcastReceiveThread = new BroadcastReceiveThread(SERVER_PROADCAST_THREAD_PORT);
        mServerBroadcastReceiveThread.setMessageListener(this);
        mSocketClientThread = new ClientConnectionThread();
        mSocketClientThread.setNewMessageReceiveListener(this);
    }

    @Override
    public void onNewMessageReceived(String threadName, String message) {
        Log.d(TAG, "onNewMessageReceive threadName = " + threadName + " message = " + message);
        publishMessage("onNewMessageReceive threadName = " + threadName + " message = " + message);
        if (TextUtils.equals(threadName, mSocketClientThread.getName())) {
            publishMessage(message);
        } else if (TextUtils.equals(threadName, mServerBroadcastReceiveThread.getName())) {
            mServerIp = message.substring(0, message.indexOf(":"));
            mServerPort = Integer.parseInt(message.substring(message.indexOf(":") + 1,
                    message.length()));
            if (!mSocketClientThread.isConnected()) {
                mSocketClientThread.start();
            }
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent == null) {
            return super.onStartCommand(intent, flags, startId);
        }
        String action = intent.getAction();
        Log.d(TAG, "onStartCommand ACITON = " + action);
        if (ACTION_CLIENT_INT.equals(action)) {
            // Client in , first listen to the server broadcast
            if (!mServerBroadcastReceiveThread.isThreadRuning()) {
                mServerBroadcastReceiveThread.start();
            }
            if (!mSocketClientThread.isConnected()) {
                // second send client broadcast to server.
                new BroadcastSenderTask(new SendDoneListener() {
                    @Override
                    public void sendDone(boolean success) {
                        Toast.makeText(SocketClientService.this, "Send Broadcast done",
                                Toast.LENGTH_SHORT).show();
                    }
                }).execute(CLIENT_BROADCAST_THREAD_PORT + "", "New_Client_in");
            }
        } else if (ACTION_CLIENT_OUT.equals(action)) {
            if (mSocketClientThread.isConnected()) {
                mSocketClientThread.stopRuning();
            }
            if (mServerBroadcastReceiveThread.isThreadRuning()) {
                mServerBroadcastReceiveThread.stopReceive();
            }
        }
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new MyClientBinder();
    }

    public class MyClientBinder extends Binder {
        public SocketClientService getService() {
            return SocketClientService.this;
        }
    }

    private class ClientConnectionThread extends SocketClientConnectionThread {
        private Socket socket;

        public ClientConnectionThread() {
            super("client_socket_connection_thread");
        }

        @Override
        protected Socket createConnectionSocket() {
            try {
                socket = new Socket(mServerIp, mServerPort);
                Log.d(TAG, "conected to " + mServerIp);
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return socket;
        }

        @Override
        protected void releaseServerSocket() {
            super.releaseServerSocket();
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
